/****************************************************************
 *This file is thread-three.c
 ****************************************************************/

#include "include.h"

/****************************************************************
 *This function is thread3
 *	(1)create socket,listen port,process command
 ****************************************************************/
void *thread3(void *str)
{
	int sockfd, new_fd;
	struct sockaddr_in my_addr;
	struct sockaddr_in their_addr;
	unsigned int sin_size;

	//int recvTimeout = SOCKET_REV_TIMETOUT;		
	//int sendTimeout = SOCKET_SEND_TIMETOUT;	

	unsigned int listen_port = 0;
	unsigned int opt_fd = 0;

	// 新增发送数据相关的局部变量
	unsigned int next_send_num = 0;
	unsigned int now_ops_place = 0;
	char send_buf_temp[2000];
	int    once_send_len = 0; 
	unsigned int temp_send_len = 0;
	int ret = 0;

	// 将线程变成独立的线程
	pthread_detach(pthread_self());

	// 获取监听端口号
	listen_port  = *((unsigned int *)str);
	opt_fd = listen_port;
	opt_fd -= HITMC_START_PORT_TWO;

	// 释放申请的空间
	//free(str);

	// 建立通信用套接字
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		fprintf(stderr,"sockfd create error!\n");
		system("touch thread_two_sockfd_create_error");
   	}
	
	// 配置端口，可以重新绑定
	//setsockopt(sockfd,   SOL_SOCKET,   SO_REUSEADDR,   &opt,   &len);

	// 绑定本地端口
	while(1){
		if(listen_port >= (HITMC_START_PORT_TWO + 1000)){
			listen_port = HITMC_START_PORT_TWO;
		}

		bzero(&my_addr, sizeof(my_addr));
		my_addr.sin_family=AF_INET;
		my_addr.sin_port=htons(listen_port);
		my_addr.sin_addr.s_addr = INADDR_ANY;
		if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == 0)
		{
			//fprintf(stderr,"bind port : %d ok !\n", listen_port);
			break;
		}
		//fprintf(stderr,"bind port : %d err !\n", listen_port);
		listen_port ++;
	}
	*((unsigned int *)str) = listen_port;
	fprintf(stderr,"bind port : %d!\n", listen_port);

	// 监听端口
	if (listen(sockfd, SOMAXCONN) == -1)
	{
		fprintf(stderr,"sockfd listen error!\n");
		system("touch thread_three_sockfd_listen_error");
	}

	// 清空局部变量
	bzero(&their_addr, sizeof(their_addr));

	// 记录连接的套接字
	udp_socket_fd_two[opt_fd] = sockfd;

	fprintf(stderr,"thread %d, %d port running\n", listen_port, udp_socket_fd_two[opt_fd]);
	ack_udp_upload_flag[opt_fd] = FLAG_VALID;

	// 并发服务器，进行提供服务
	while(1)
	{
		// 等待客户端连接
		sin_size = sizeof(struct sockaddr_in);
		new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
		if (new_fd <= 0)
		{
			if(udp_socket_status[opt_fd] == FLAG_INVALID){
				fprintf(stderr,"quit %d thread!\n", listen_port);
				break;
			} else {
				fprintf(stderr,"sockfd accept error!\n");
				continue;
			}
		}

		// 设置发送和接收超时
		//setsockopt(new_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&recvTimeout, sizeof(int));
		//setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&sendTimeout, sizeof(int));

		fprintf(stderr,"accept opt_fd %d, listen_port: %d, udp_socket_fd_two[opt_fd]: %d, new_fd: %d\n", opt_fd, listen_port, udp_socket_fd_two[opt_fd], new_fd);

		while(1){
			// 阻塞等待上位机发送指令
			ret = read(new_fd, send_buf_temp, TCP_RECEIVE_ONCE_NUM);
			//fprintf(stderr,"upload ret: %d\n", ret);

			// 上位机退出该线程
			if(ret <= 0){
				// 标志置为无效
				udp_upload_flag[opt_fd] = FLAG_INVALID;

				fprintf(stderr,"quit upload new_fd: %d\n", new_fd);

				// 关闭接收套接字
				close(new_fd);
				break;
			}

			// 等待接收标志有效
			while(udp_upload_flag[opt_fd] == FLAG_INVALID){
				usleep(100);
			}
			udp_upload_flag[opt_fd] = FLAG_INVALID;


			// 发送数据
			next_send_num = udp_upload_count[opt_fd];
			now_ops_place = 0;
			ret = 0;
			once_send_len = 0;
			while(next_send_num > 0){
				// 计算本次发送数据量
				if(next_send_num >= TCP_RECEIVE_ONCE_NUM){
					once_send_len = TCP_RECEIVE_ONCE_NUM;
				} else {
					once_send_len = next_send_num;
				}

				// 填充发送缓冲区到局部变量中
				for(temp_send_len = 0; temp_send_len < once_send_len; temp_send_len ++){
					send_buf_temp[temp_send_len] = udp_upload_data_p[opt_fd][now_ops_place + temp_send_len];
				}

				// 发送数据
				ret = write(new_fd, send_buf_temp, once_send_len);

				// 判断是否有异常
				if(ret < 0){
					// 判断是否为信号打断
					if((ret < 0) && (errno == EINTR)){
						continue;
					} else {
						break;
					}
				}

				// 计算下次发送的位置和大小
				next_send_num -= ret;
				now_ops_place += ret;
			}

			// 接收完毕数据，置应答有效
			ack_udp_upload_flag[opt_fd] = FLAG_VALID;
		}
	}

	return NULL;
}
